package com.example.git_androidlxj;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import java.util.Stack;

public class MainActivity extends AppCompatActivity {
    // UI组件
    private TextView calculationDisplay;//显示计算过程的文本框
    private TextView resultDisplay;//显示计算结果的文本框
    //状态变量
    private String currentInput="";//当前输入表达式
    private  boolean lastInputWasOperator=false;//上次输入是否为运算符
    private  boolean lastInputWasEquals=false;//上次是否按了等号
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        /*初始化UI组件*/
        calculationDisplay =findViewById(R.id.calculation_display);//获取计算过程显示框的引用
        resultDisplay=findViewById(R.id.result_display);//获取结果显示框的引用
        /*数字按钮初始化*/
        //定义数字按钮ID数组(0-9)
        int[] numberButtonIds ={
                R.id.btn_0,R.id.btn_1,R.id.btn_2,R.id.btn_3,R.id.btn_4,
                R.id.btn_5,R.id.btn_6,R.id.btn_7,R.id.btn_8,R.id.btn_9
        };
        //遍历数字按钮数组，为每个按钮设置点击监听
        for(int id:numberButtonIds){
            findViewById(id).setOnClickListener(this::onNumberClick);
        }
        /*运算符按钮初始化*/
        //定义运算符按钮ID数组(加减乘除、小数点、左右括号)
        int[] operatorButtonIds = {
                R.id.btn_add,R.id.btn_subtract,R.id.btn_multiply,R.id.btn_divide,
                R.id.btn_decimal,R.id.btn_parentheses_left,R.id.btn_parentheses_right
        };
        //遍历运算符按钮数组，为每个按钮设置点击监听
        for(int id:operatorButtonIds){
            findViewById(id).setOnClickListener(this::onOperatorClick);
        }
        /*功能按钮初始化*/
        //等号按钮点击监听(计算结果)
        findViewById(R.id.btn_equals).setOnClickListener(this::onEqualsClick);
        //清除按钮点击监听(清空输入)
        findViewById(R.id.btn_clear).setOnClickListener(this::onClearClick);
        //删除按钮点击监听(删除最后一个字符)
        findViewById(R.id.btn_delete).setOnClickListener(this::onDeleteClick);
    }
    /*处理数字按钮点击事件的方法
    当用户点击0~9数字按钮时触发
    view被点击的按钮视图对象*/
    private void onNumberClick(View view) {
        //如果上次按了等号，则清空当前输入
        if(lastInputWasEquals){
            //清空当前输入内容，准备开始新的计算
            currentInput = "";
            //重置等号状态标志
            lastInputWasEquals = false;
        }
        //将View对象转换为Button对象
        Button button = (Button) view;
        //获取按钮上的文本内容(数字字符)
        String number = button.getText().toString();
        //将数字追加到当前输入字符串末尾
        currentInput +=number;
        //更新计算过程显示框内容
        updateCalculationDisplay();
        /*状态标记:因为当前输入的是数字，所以标记“上次输入不是运算符”这个状态会影响后续运算符按钮的处理逻辑*/
        lastInputWasOperator = false;//标记当前输入不是运算符
    }
    /*处理运算符按钮点击事件的方法
    当用户点击加减乘除、括号等运算符按钮时触发
    view被点击的按钮视图对象*/
    private void onOperatorClick(View view) {
        //获取被点击的按钮对象
        Button button = (Button) view;
        //获取按钮上的运算符文本
        String operator= button.getText().toString();
        /*特殊处理：当上次操作是按了等号(=)后输入运算符时
                但排除括号运算符的情况(括号需要特殊处理)*/
        if(lastInputWasEquals && !operator.equals("(")&&!operator.equals(")")){
            //将结果显示框的内容作为新的输入
            currentInput = resultDisplay.getText().toString();
            //重置等号状态标志
            lastInputWasEquals=false;
        }
        /*根据运算符类型进行不同处理*/
        switch (operator){
            case "-"://负号处理
                //允许在表达式开头或运算符后输入负号
                if (currentInput.isEmpty()||lastInputWasOperator){
                    currentInput+=operator;//直接添加负号
                    lastInputWasOperator=false;//标记为非运算符(负号是数字的一部分)
                }else {
                    //否则作为减号运算符处理
                    addOperator(operator);
                }
                break;
            case "("://左括号处理
                /*允许在以下情况直接添加左括号：1.表达式开头2.前一个输入是运算符3.前一个字符已经是左括号*/
                if (currentInput.isEmpty()||lastInputWasOperator||currentInput.charAt(currentInput.length()-1)=='('){
                    currentInput+=operator;
                    lastInputWasOperator=false;
                }else {
                    //在数字和左括号之间自动添加乘号
                    currentInput+="×" + operator;//自动添加乘号
                    lastInputWasOperator=false;
                }
                break;
            case ")"://右括号处理
                //只有在左括号比右括号多时才被允许添加右括号，确保右括号匹配
                if (!currentInput.isEmpty()&&countOccurrences(currentInput,'(') > countOccurrences(currentInput,')')){
                    currentInput+=operator;
                    lastInputWasOperator=false;
                }
                break;
            default://普通运算符处理(加减乘除)
                addOperator(operator);
                break;
        }
        //更新计算过程显示框
        updateCalculationDisplay();
    }
    /*添加运算符到当前输入表达式的方法，处理运算符替换逻辑，确保表达式语法正确*/
    private void addOperator(String operator) {
        //检查当前输入是否为空
        if(currentInput.isEmpty()){
            return;//空输入时不添加运算符
        }
        //获取当前输入表达式的最后一个字符
        char lastChar = currentInput.charAt(currentInput.length()-1);
        //运算符替换逻辑：如果最后一个字符已经是运算符(加减乘除)，则替换为新的运算符(避免连续多个运算符)
        if(lastChar=='+'||lastChar=='-'||lastChar=='×'||lastChar=='÷'){
            //截取除最后一个字符外的所有内容
            currentInput=currentInput.substring(0,currentInput.length()-1)+operator;
        }else {
            //如果最后一个字符不是运算符，直接追加新运算符
            currentInput+=operator;
        }
        //标记最后一个输入是运算符(影响后续输入处理)
        lastInputWasOperator=true;
    }
    /*处理等号(=)按钮点击事件的方法，负责计算当前输入表达式的最终结果，view被点击的等号按钮视图对象*/
    private  void onEqualsClick(View view){
        //检查当前输入是否为空
        if(currentInput.isEmpty()){
            return;//空输入不执行计算
        }
        try{
            //括号匹配检查：确保表达式中的左括号和右括号数量相等
            if(countOccurrences(currentInput,'(')!=countOccurrences(currentInput,')')){
                //显示括号不匹配提示
                Toast.makeText(this, "括号不匹配", Toast.LENGTH_SHORT).show();
                return;
            }
            //符号转换：将显示用的乘除符号(×÷)转换为计算用的(*/)
            String expression =currentInput.replace('×','*').replace('÷','/');
            //调用表达式求值方法计算结果
            double result = evaluateExpression(expression);
            //格式化并显示计算结果
            resultDisplay.setText(formatResult(result));
            //标记最后一次输入是等号(影响后续输入处理)
            lastInputWasEquals=true;
        }catch (Exception e){
            //捕获并处理计算过程中可能出现的异常
            Toast.makeText(this, "无效表达", Toast.LENGTH_SHORT).show();
        }
    }
    /*处理清除按钮点击事件的方法，重置计算器所有状态和显示内容，view被点击的清除按钮视图对象*/
    private void onClearClick(View view){
        //清空当前输入表达式
        currentInput="";
        //清空计算过程显示区域
        calculationDisplay.setText("");
        //清空结果展示区域
        resultDisplay.setText("");
        //重置运算符输入状态标志
        lastInputWasOperator=false;
        //重置等号输入状态标志
        lastInputWasEquals=false;
    }
    /*处理删除按钮点击事件的方法，删除当前输入表达式的最后一个字符，view被点击的删除按钮视图对象*/
    private void onDeleteClick(View view){
        //检查当前输入是否为空
        if(!currentInput.isEmpty()){
            //获取当前输入表达式的最后一个字符
            char lastChar = currentInput.charAt(currentInput.length()-1);
            //删除最后一个字符（实现退格功能）
            currentInput = currentInput.substring(0,currentInput.length()-1);
            //运算符状态更新:如果删除的是运算符，更新状态运算符状态标志
            if(lastChar=='-'||lastChar=='+'||lastChar=='×'||lastChar=='÷'){
                lastInputWasOperator=false;
            }
            //更新计算显示框内容
            updateCalculationDisplay();
        }
    }
    /*更新计算显示框内容的方法，将当前输入表达式显示在计算显示区域*/
    private void updateCalculationDisplay() {
        //设置计算显示框的文本为当前输入表达式
        calculationDisplay.setText(currentInput);
    }
    /*格式化计算结果的方法，对计算结果进行格式化处理，整数结果不显示小数部分
     * result需要格式化的计算结果(double类型)，格式化后的字符串显示*/
    private String formatResult(double result) {
        //检查结果是否为正数(比较double值和long值是否相等)
        if (result==(long) result){
            //如果是整数，使用整型格式输出(不显示小数部分)
            return String.format("%d",(long)result);
        }else{
            //如果是小数，保持原样输出
            return String.format("%s",result);
        }
    }
    /*统计字符串中特定字符出现次数的方法，str需要搜索的字符串，ch需要统计的目标字符，count目标字符在字符串出现的次数*/
    private int countOccurrences(String str, char ch) {
        int count=0;//初始化计数器
        //遍历字符串的每个字符
        for (int i=0;i<str.length();i++){
            //检查当前字符是否匹配到目标字符
            if (str.charAt(i)==ch){
                count++;//匹配则计数器加1
            }
        }
        return count;//返回最终统计结果
    }
    //使用双栈法计算表达式值，实现四则运算和括号优先级处理，expression要计算的数学表达式字符串
    private double evaluateExpression(String expression) {
        //预处理：移除表达式中的所有空白字符
        expression = expression.replaceAll("\\s+","");
        //初始化数字栈(存储操作数)
        Stack<Double> numbers = new Stack<>();
        //初始化运算符栈(存储运算符和括号)
        Stack<Character> operators = new Stack<>();
        //遍历表达式每个字符
        for(int i=0;i<expression.length();i++){
            char c =expression.charAt(i);
            //处理数字和小数点
            if (Character.isDigit(c)||c=='.'){
                StringBuffer numStr = new StringBuffer();
                //提取完整数字(支持多位整数和小数)
                while (i<expression.length()&&(Character.isDigit(expression.charAt(i))||expression.charAt(i)=='.')){
                    numStr.append(expression.charAt(i++));
                }
                i--;//回退索引(因为循环会i++)
                //将数字字符串转为double并入栈
                numbers.push(Double.parseDouble(numStr.toString()));
            }
            //处理左括号
            else if(c=='('){
                operators.push(c);//左括号直接入栈
            }
            //处理右括号
            else if (c==')') {
                //计算括号内的表达式，直到遇到左括号
                while(operators.peek()!='('){
                    //取运算符、取右操作数、取左操作数
                    numbers.push(applyOperation(operators.pop(),numbers.pop(),numbers.pop()));
                }
                operators.pop();//弹出左括号
            }
            //处理运算符(+-*/)
            else if (c=='+'||c=='-'||c=='*'||c=='/') {
                //处理运算符优先级:当前运算符优先级《=栈顶运算符时先计算
                while (!operators.empty() && hasPrecefence(c,operators.peek())){
                    numbers.push(applyOperation(operators.pop(),numbers.pop(),numbers.pop()));
                }
                operators.push(c);//当前运算符入栈
            }
        }
        //处理栈中剩余运算符
        while (!operators.empty()){
            numbers.push(applyOperation(operators.pop(),numbers.pop(),numbers.pop()));
        }
        //最总结果在数字栈顶
        return numbers.pop();
    }
    /*检查运算符优先级方法，比较两个运算符的优先级，判断op1是否应该优先于op2计算
     * op1当前运算符,op2栈顶运算符,true表示op2优先级>=op1，false表示op1优先级>op2*/
    private boolean hasPrecefence(char op1, char op2) {
        //如果栈顶是括号，当前运算符优先级更高
        if (op2=='('||op2==')'){
            return false;
        }
        //如果当前是*/而栈顶是+-，当前运算符优先级更高
        if ((op1=='*'||op1=='/')&&(op2=='+'||op2=='-')){
            return false;
        }
        //其他情况栈顶运算符优先级更高或相等
        return true;
    }
    //执行基本算术运算的方法，op运算符（+-*/）,b右操作数,a左操作数,return运算结果,ArithmeticException当除数为0时抛出异常
    private double applyOperation(char op, double b, double a) {
        switch (op){
            case '+':return a+b;//加法运算
            case '-':return a-b;//减法运算
            case '*':return a*b;//乘法运算
            case '/':
                //除法运算前检查除数是否为0
                if (b==0){
                    throw new ArithmeticException("除数不能为0");
                }
                return a/b;//除法运算
        }
        return 0;//默认返回0(实际不会执行到这里)
    }
}